package com.adee.gulimall.util.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;

/**
 * JWT的数据结构
 * jwt头：JWT头部分是一个描述JWT元数据的JSON对象
 * 2）有效载荷：七个默认字段+自定义私有字段
 *
 * 3）签名=HMACSHA256(base64UrlEncode(header)+"."+base64UrlEncode(payload),secret)
 *
 *
 *
 * 第一部分 ：JWT头
 * base64UrlEncode(header)—>字符串
 * # JWT头部分是一个描述JWT元数据的JSON对象，通常如下所示。
 * {
 *    "alg": "HS256",
 *    "typ": "JWT"
 * }
 * # 1）alg属性表示签名使用的算法，默认为HMAC SHA256（写为HS256）；
 * # 2）typ属性表示令牌的类型，JWT令牌统一写为JWT。
 * # 3）最后，使用Base64 URL算法将上述JSON对象转换为字符串保存。
 *
 * 第二部分： 有效载荷 没有敏感数据的用户信息
 * base64UrlEncode(payload)—>字符串
 * #1、有效载荷部分，是JWT的主体内容部分，也是一个JSON对象，包含需要传递的数据。 JWT指定七个默认 字段供选择。
 * '''
 * iss：发行人
 * exp：到期时间
 * sub：主题
 * aud：用户
 * nbf：在此之前不可用
 * iat：发布时间
 * jti：JWT
 * ID用于标识该JWT
 * '''
 *
 * #2、除以上默认字段外，我们还可以自定义私有字段，如下例：
 * {
 * "sub": "1234567890",
 * "name": "chongchong",
 * "admin": true
 * }
 * #3、注意 默认情况下JWT是未加密的，任何人都可以解读其内容，因此不要构建隐私信息字段，存放保密信息，以防 止信息泄露。
 * JSON对象也使用Base64 URL算法转换为字符串保存
 *
 *
 * 第三部分： 签名哈希
 * 签名=HMACSHA256(base64UrlEncode(header)+"."+base64UrlEncode(payload),secret)
 *
 * # 1.签名哈希部分是对上面两部分数据签名，通过指定的算法生成哈希，以确保数据不会被篡改。
 * # 2.首先，需要指定一个密码（secret），该密码仅仅为保存在服务器中，并且不能向用户公开。
 * # 3.然后，使用标头中指定的签名算法（默认情况下为HMAC SHA256）根据以下公式生成签名。
 * # 4.HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload),secret)
 * # 5.在计算出签名哈希后，JWT头，有效载荷和签名哈希的三个部分组合成一个字符串，每个部分用"."分 隔，就构成整个JWT对象
 */
@Slf4j
public class JwtUtils {

    private static final String secret = "1qazXSW@,.;'/87ujy27J"; // 加解密用的密码
    private static final long expire = 7*24*60*60; // 多少秒过期
    public static final String header = "token"; // 保存在http请求头名为 token

    public static void main(String[] args) {
        String token = generateToken(3);
        System.out.println(token);
        Claims claims = getClaimByToken(token);
        System.out.println(claims.getSubject());
        Claims claims1 = getClaimByToken(token.substring(1));
        System.out.println(claims1.getSubject());
    }

    /**
     * 生成jwt token
     */
    public static String generateToken(long userId) {
        Date nowDate = new Date();
        //过期时间
        Date expireDate = new Date(nowDate.getTime() + expire * 1000);

        return Jwts.builder()
                .setHeaderParam("typ", "JWT")
                .setSubject(userId+"")
                .setIssuedAt(nowDate)
                .setExpiration(expireDate)
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }

    public static Claims getClaimByToken(String token) {
        try {
            return Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
        }catch (Exception e){
            log.warn("validate is token error ", e);
            return null;
        }
    }

    // 判断token是否有效：能正常解析，并且未过期，则有效，否则无效
    public static boolean isValid(String token) {
        Claims claims = getClaimByToken(token);
        if (claims != null) {
            Date expiration = claims.getExpiration();
            Date now = new Date();
            return expiration.after(now);
        }
        return false;
    }

    /**
     * token是否过期
     * @return  true：过期
     */
    public boolean isTokenExpired(Date expiration) {
        return expiration.before(new Date());
    }

}
